package stu.kurs.services.impl;

import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;


import stu.kurs.domain.DomainObject;
import stu.kurs.exceptions.ServiceException;
import stu.kurs.services.IGenericService;

public class GenericService<T extends DomainObject> implements IGenericService<T>{
	
	@PersistenceContext(unitName="y_london")
	protected EntityManager em;
	private Class<T> persistaceClass;
	
	public GenericService(Class<T> persistaceClass){
		this.persistaceClass = persistaceClass;
	}

	public T findById(Integer id) throws ServiceException{
		T entity = null;
		try{
			entity = em.find(persistaceClass, id);
		} 
		catch (NoResultException e){
			return null;
		}
		catch (Exception e){
			throw new ServiceException(e);
		} 
		return entity;
	}

	public List<T> findAll() throws ServiceException{
		List<T> result = null;
		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<T> cq = cb.createQuery(persistaceClass);
		TypedQuery<T> q = em.createQuery(cq); 
		try{
			result = q.getResultList();
		}
		catch (Exception e){
			throw new ServiceException(e);
		} 
		return result;
	}

	public T save(T entity) throws ServiceException{
		if (entity == null) {
			throw new IllegalArgumentException("Entity for saving cannot be null!");
		}
		try{
			if (entity.getId() == null) em.persist(entity);
			else em.merge(entity);
		} 
		catch (Exception e){
			throw new ServiceException(e);
		}
		return entity;
	}

	public void delete(T entity) throws ServiceException{
		try{
			entity = em.merge(entity);
			em.remove(entity);
		} 
		catch (Exception e){
			throw new ServiceException(e);
		}
	}

	public Integer getAllCount() throws ServiceException{
		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<Long> cq = cb.createQuery(Long.class);
		Root<T> t = cq.from(persistaceClass);
		cq.select(cb.count(t));
		TypedQuery<Long> tq = em.createQuery(cq);
		Integer count = null;
		try{
			count = tq.getSingleResult().intValue();
		}
		catch (Exception e){
			throw new ServiceException(e);
		}
		return count;
	}
}
